"""
result_visualizer.py - 处理结果可视化类

该文件包含用于可视化交通事件处理结果的类和方法。
"""

import matplotlib.pyplot as plt
from typing import Dict, Any, Optional, Tuple
from matplotlib.figure import Figure
from matplotlib.axes import Axes
import os

# 确保可视化结果目录存在
VISUALIZATION_DIR = "D:\\ALOT数据库\\visualizations"
os.makedirs(VISUALIZATION_DIR, exist_ok=True)

class ResultVisualizer:
    """处理结果可视化类"""

    def __init__(self):
        """初始化可视化器，设置样式和颜色"""
        plt.style.use('seaborn-v0_8')  # 使用seaborn样式
        self._setup_colors()  # 设置颜色配置
        self._setup_fonts()  # 设置字体配置

    def _setup_colors(self):
        """设置颜色配置"""
        self.colors = {
            'info': '#4C72B0',  # 信息色
            'warning': '#DD8452',  # 警告色
            'error': '#C44E52',  # 错误色
            'success': '#55A868',  # 成功色
            'background': '#F0F0F0'  # 背景色
        }

    def _setup_fonts(self):
        """设置字体配置"""
        plt.rcParams.update({
            'font.family': 'sans-serif',  # 无衬线字体
            'font.sans-serif': ['Microsoft YaHei', 'SimHei'],  # 中文字体
            'axes.unicode_minus': False  # 解决负号显示问题
        })

    def visualize_result(self, result: Dict[str, Any],
                         figsize: Tuple[int, int] = (14, 10)) -> Optional[Figure]:
        """主可视化方法

        参数:
            result: 处理结果字典
            figsize: 图形大小，默认为(14, 10)

        返回:
            可视化图形对象或None
        """
        if not result or result.get("status") != "success":
            print("无有效结果可可视化")
            return None

        try:
            # 创建图形和子图布局
            fig = plt.figure(figsize=figsize, facecolor=self.colors['background'])
            fig.suptitle("交通事件处理结果可视化", fontsize=16, y=1.02)

            # 创建2x2的子图网格
            gs = fig.add_gridspec(2, 2)
            ax1 = fig.add_subplot(gs[0, 0])  # 基本信息
            ax2 = fig.add_subplot(gs[0, 1])  # 事件严重性
            ax3 = fig.add_subplot(gs[1, 0])  # 处理方案
            ax4 = fig.add_subplot(gs[1, 1])  # 资源分配

            # 绘制各个子图
            self._draw_basic_info(result, ax1)
            self._draw_severity_chart(result, ax2)
            self._draw_options_chart(result, ax3)
            self._draw_resources_chart(result, ax4)

            plt.tight_layout()  # 自动调整子图间距
            return fig
        except Exception as e:
            print(f"可视化过程中发生错误: {str(e)}")
            return None

    def _draw_basic_info(self, result: Dict[str, Any], ax: Axes) -> None:
        """绘制基本信息子图

        参数:
            result: 处理结果字典
            ax: 要绘制的子图对象
        """
        event = result["event_info"]
        loc = result["location"]

        # 构建基本信息文本
        info_text = (
            f"事件ID: {result.get('event_id', 'N/A')}\n"
            f"类型: {event['type']}\n"
            f"位置: {loc['area_type']}区域\n"
            f"坐标: ({loc['longitude']:.4f}, {loc['latitude']:.4f})\n"
            f"警报级别: {result['alert_level']}\n"
            f"时间: {result['timestamp'][:19]}"  # 截取到秒
        )

        # 添加文本到子图
        ax.text(0.1, 0.7, info_text, fontsize=11,
                bbox=dict(facecolor='white', alpha=0.8))
        ax.set_title("事件基本信息", fontsize=12, pad=10)
        ax.axis('off')  # 关闭坐标轴

    def _draw_severity_chart(self, result: Dict[str, Any], ax: Axes) -> None:
        """绘制事件严重性图表

        参数:
            result: 处理结果字典
            ax: 要绘制的子图对象
        """
        event = result["event_info"]
        # 定义要显示的指标
        metrics = {
            '可信度': event['confidence'],
            '严重程度': event['severity'],
            '人群密度': event['crowd_density'],
            '交通影响': result['predicted_impact']['traffic_impact']
        }

        # 为每个指标分配颜色
        colors = [self.colors['info'], self.colors['warning'],
                  self.colors['error'], self.colors['success']]

        # 绘制柱状图
        bars = ax.bar(metrics.keys(), metrics.values(), color=colors)

        # 在柱子上方添加数值标签
        for bar in bars:
            height = bar.get_height()
            ax.text(bar.get_x() + bar.get_width() / 2, height,
                    f"{height:.2f}", ha='center', va='bottom')

        ax.set_ylim(0, 1.1)  # 设置Y轴范围
        ax.set_title("事件指标评估", fontsize=12)
        ax.grid(True, linestyle='--', alpha=0.6)  # 添加网格线

    def _draw_options_chart(self, result: Dict[str, Any], ax: Axes) -> None:
        """绘制处理方案图表

        参数:
            result: 处理结果字典
            ax: 要绘制的子图对象
        """
        options = result.get('processing_options', [])
        if not options:
            # 如果没有处理方案，显示提示信息
            ax.text(0.3, 0.5, "无处理方案", fontsize=12)
            ax.axis('off')
            return

        # 提取方案信息
        names = [opt['name'] for opt in options]
        necessity = [opt['necessity'] for opt in options]
        levels = [opt['level'] for opt in options]

        # 根据级别设置颜色
        colors = []
        for level in levels:
            if level == 'high':
                colors.append(self.colors['error'])
            elif level == 'medium':
                colors.append(self.colors['warning'])
            else:
                colors.append(self.colors['info'])

        # 绘制水平条形图
        bars = ax.barh(names, necessity, color=colors)
        # 添加必要性数值标签
        for i, (name, nec) in enumerate(zip(names, necessity)):
            ax.text(nec + 0.02, i, f"{nec:.2f}", va='center')

        ax.set_xlim(0, 1.1)  # 设置X轴范围
        ax.set_title("处理方案必要性 (颜色表示级别)", fontsize=12)
        ax.grid(True, linestyle='--', alpha=0.6)  # 添加网格线

    def _draw_resources_chart(self, result: Dict[str, Any], ax: Axes) -> None:
        """绘制资源分配图表

        参数:
            result: 处理结果字典
            ax: 要绘制的子图对象
        """
        resources = result.get('resource_allocation', [])
        if not resources:
            # 如果没有资源分配，显示提示信息
            ax.text(0.3, 0.5, "无资源分配", fontsize=12)
            ax.axis('off')
            return

        # 统计资源类型和数量
        resource_types = {}
        for res in resources:
            name = res.split('×')[0].strip()  # 提取资源名称
            count = int(res.split('×')[1]) if '×' in res else 1  # 提取数量
            resource_types[name] = resource_types.get(name, 0) + count

        labels = list(resource_types.keys())
        sizes = list(resource_types.values())
        colors = plt.cm.Pastel1(range(len(labels)))  # 使用Pastel1颜色映射

        # 绘制饼图
        wedges, texts, autotexts = ax.pie(
            sizes, labels=labels, autopct='%1.1f%%',
            startangle=90, colors=colors,
            textprops={'fontsize': 10},
            wedgeprops={'edgecolor': 'w', 'linewidth': 1})

        ax.set_title("资源分配比例", fontsize=12)
        ax.axis('equal')  # 确保饼图是圆形


    def save_visualization(self, result: Dict[str, Any],
                           filename: str = None) -> bool:
        """保存可视化结果到文件"""
        fig = self.visualize_result(result)
        if fig is None:
            return False

        if filename is None:
            filename = f"result_visualization_{result.get('event_id', 'unknown')}.png"

        filepath = os.path.join(VISUALIZATION_DIR, filename)

        try:
            fig.savefig(filepath, dpi=300, bbox_inches='tight')
            plt.close(fig)
            return True
        except Exception as e:
            print(f"保存可视化结果失败: {str(e)}")
            return False

if __name__ == "__main__":
    from main import _create_test_case

    visualizer = ResultVisualizer()
    result = _create_test_case
    fig = visualizer.visualize_result(result)
    if fig:
        plt.show()